# Copyright (c) 2007 Fabio Makoto Akita
# 
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# Author: AkitaOnRails (www.akitaonrails.com)
# Support: Surgeworks LLC (www.surgeworks.com)

# Creates the means to stub the Net::HTTP methods
# that would require a live online server 
# now, with the stubbing, it doesn't have to hit the network
# It only mocks calls to the 'start' method, which is the one used
# through the syncs_helper.rb module
# Preset response_obj using the Net::HTTP.build_response method
# Check the 'sent' parameters from the Net::HTTP.request variable
class Test::Unit::TestCase
  def stub_net(response_obj = nil)
    begin
      Net::HTTP.class_eval do
        alias :__start__ :start
        alias :__request__ :request

        cattr_accessor :request, :response_obj
      
        def start
          if block_given?
            yield self
          end
          # you can set response_obj argument as a block that gets evaluated here
          # this is useful if you have to test a method that calls
          # start twice and you need different responses for each depending
          # on the current $request. Use the Net::Request#form_data parser
          # implemented below
          unless Net::HTTP.response_obj
            Net::HTTP.build_response('200')
          else
            if response_obj.is_a? Proc
              Net::HTTP.response_obj.call
            else
              Net::HTTP.response_obj
            end
          end
        end
        
        def request(req, body = nil, &block)
          Net::HTTP.request = req
        end
        
        # build a mock response object
        def self.build_response(options = {})
          code = options[:code] || '200'
          msg = options[:msg] || ''
          response = Net::HTTPResponse::CODE_TO_OBJ[code.to_s].new('1.1', code, msg)
          response.fake_body = options[:body] if options[:body]
          response['set-cookie'] = '12345; 666'
          response
        end
      end
      
      Net::HTTPRequest.class_eval do
        # very naive parameter parsing
        def form_data
          return @form_data if @form_data
          return nil if body.nil?
          @form_data = {}
          body.split("&").each do |token|
            pair = token.split("=")
            @form_data.merge!(pair.first => pair.last)
          end
          @form_data.symbolize_keys!
        end
        
        # check if the returned struct has all the required keys
        def has_keys?(required_keys = [])
          return false if form_data.blank?
          form_data.each do |key, value|
            required_keys.delete(key.to_s)
          end
          required_keys.size == 0
        end
      end
      
      Net::HTTPResponse.class_eval do
        alias :__body__ :body
        
        # allows to set a false body
        attr_accessor :fake_body
        
        def body
          fake_body
        end
      end
      
      Net::HTTP.response_obj = response_obj
      
      # run the unit test
      yield if block_given?
    ensure
      # rollback the Net::HTTP stubs
      Net::HTTP.class_eval do
        alias :start :__start__ 
        alias :request :__request__ 
      end
      
      Net::HTTPResponse.class_eval do
        alias :body :__body__
      end
    end
  end
end